﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using MvcEngine.Core.Repositories;
using MvcEngine.Core.Utils;
using MvcEngine.Core.Helpers;
using MvcEngine.Core.Base;
using MvcEngine.Core.Pagination;

namespace MvcEngine.Core.Content
{
    public class ContentManager : BaseManager, IContentManager
    {
        private readonly IPageRepository pageRepository = null;
        private readonly IControlRepository controlRepository = null;
        private readonly IPageContentRepository pageContentRepository = null;
        private readonly IContainerRepository containerRepository = null;
        private readonly IModuleRepository moduleRepository = null;
        private readonly IPermissionRepository permissionRepository = null;

        public static IContentManager Current
        {
            get { return IoC.Resolve<IContentManager>(); }
        }

        public ContentManager(IPageRepository pageRepository, IPageContentRepository pageContentRepository, IControlRepository controlRepository, IContainerRepository containerRepository, IModuleRepository moduleRepository, IPermissionRepository permissionRepository)
        {
            this.pageRepository = pageRepository;
            this.pageContentRepository = pageContentRepository;
            this.controlRepository = controlRepository;
            this.containerRepository = containerRepository;
            this.moduleRepository = moduleRepository;
            this.permissionRepository = permissionRepository;
        }

        #region Page methods

        public IList<Page> GetPages(bool onlyVisible)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageAllVisible, SiteContext.Current.Site.Id, onlyVisible), CacheKey.ContentKeys.PageCategory,
                () =>
                {
                    var pages = pageRepository.GetAll(onlyVisible, SiteContext.Current.Site.Id);
                    foreach (var item in pages)
                    {
                        this.ConvertXmlToProperties(item);
                    }
                    return pages;
                });
        }

        public IPagination<Page> GetPages(int pageIndex, int count)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageAll, SiteContext.Current.Site.Id), CacheKey.ContentKeys.PageCategory,
                () =>
                {
                    var pages = pageRepository.GetAll(SiteContext.Current.Site.Id, pageIndex, count);
                    foreach (var item in pages)
                    {
                        this.ConvertXmlToProperties(item);
                    }
                    return pages;
                });
        }

        public Page GetPage(Guid pageId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageId, pageId), CacheKey.ContentKeys.PageCategory,
                () =>
                {
                    var page = pageRepository.Get(pageId);
                    this.ConvertXmlToProperties(page);
                    return page;
                });
        }

        public Page GetPage(string pageName)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageName, SiteContext.Current.Site.Id, pageName), CacheKey.ContentKeys.PageCategory,
                () =>
                {
                    var page = pageRepository.Get(pageName, SiteContext.Current.Site.Id);
                    this.ConvertXmlToProperties(page);
                    return page;
                });
        }

        public void SavePage(Page page)
        {
            Guard.ThrowIfEmptyGuid(page.Id);

            using (var unitOfWork = UnitOfWorkHelper.Get())
            {
                var oldItem = pageRepository.Get(page.Id);
                if (oldItem != null)
                {
                    oldItem.ModifiedDate = DateTime.Now;
                    oldItem.ModifiedBy = UserContext.Current.User.Id;
                    oldItem.Name = page.Name;
                    oldItem.Title = page.Title;
                    oldItem.MenuTitle = page.MenuTitle;
                    oldItem.Keywords = page.Keywords;
                    oldItem.Description = page.Description;
                    oldItem.Header = page.Header;
                    oldItem.Visible = page.Visible;
                    oldItem.VisibleInMenu = page.VisibleInMenu;
                    oldItem.OrderNumber = page.OrderNumber;
                    oldItem.SkinId = page.SkinId;
                    oldItem.SkinTemplateId = page.SkinTemplateId;
                    oldItem.Xml = page.Fields;
                    pageRepository.Update(oldItem);
                }
                else
                {
                    page.CreatedBy = UserContext.Current.User.Id;
                    page.ModifiedBy = UserContext.Current.User.Id;
                    page.CreatedDate = DateTime.Now;
                    page.ModifiedDate = DateTime.Now;
                    page.SiteId = SiteContext.Current.Site.Id;
                    page.Xml = page.Fields;
                    pageRepository.Add(page);
                }
                unitOfWork.Commit();
            }

            CacheManager.Current.ClearCache(CacheKey.ContentKeys.PageCategory);
        }

        public void DeletePage(Guid pageId)
        {
            using (var unitOfWork = UnitOfWorkHelper.Get())
            {
                pageRepository.Delete(pageId);
                permissionRepository.DeletePagePermissions(pageId);
                unitOfWork.Commit();
            }
            CacheManager.Current.ClearCache(CacheKey.ContentKeys.PageCategory);
        }

        #endregion

        #region Page content methods

        public PageContent GetPageContent(int id)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageContentId, id), CacheKey.ContentKeys.PageContentCategory,
                () =>
                {
                    var pageContent = pageContentRepository.Get(id);
                    this.ConvertXmlToProperties(pageContent);
                    return pageContent;
                });
        }

        public IList<PageContent> GetPageContents(Guid pageId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageContentIdByPage, pageId), CacheKey.ContentKeys.PageContentCategory,
                () =>
                {
                    var list = pageContentRepository.GetByPage(pageId);
                    foreach (var item in list)
                    {
                        this.ConvertXmlToProperties(item);
                    }
                    return list;
                });
        }

        public IList<PageContentDetails> GetPageContentDetails(Guid pageId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageContentDetailsByPage, pageId), CacheKey.ContentKeys.PageContentCategory,
                () => pageContentRepository.GetPageContentDetailsByPage(pageId));
        }

        public IList<PageContent> GetPageContentsByControl(Guid controlId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.PageContentDetailsByControl, SiteContext.Current.Site.Id, controlId), CacheKey.ContentKeys.PageContentCategory,
                () =>
                {
                    var list = pageContentRepository.GetByControl(controlId, SiteContext.Current.Site.Id);
                    foreach (var item in list)
                    {
                        this.ConvertXmlToProperties(item);
                    }
                    return list;
                });
        }

        public void SavePageContent(PageContent pageContent)
        {
            pageContentRepository.Save(pageContent);
            CacheManager.Current.ClearCache(CacheKey.ContentKeys.PageContentCategory);
        }

        #endregion

        #region Control methods

        public Control GetControl(Guid controlId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ControlId, controlId), CacheKey.ContentKeys.ControlCategory,
                () => controlRepository.Get(controlId));
        }

        public IList<Control> GetControls()
        {
            return CacheManager.Current.FromCache(CacheKey.ContentKeys.ControlAll, CacheKey.ContentKeys.ControlCategory,
                () => controlRepository.GetAll());
        }

        public IList<Control> GetControls(Guid moduleId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ControlsByModule, moduleId), CacheKey.ContentKeys.ControlCategory,
                () => controlRepository.GetAllByModule(moduleId));
        }

        public Control GetControlByKey(string controlKey)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ControlKey, controlKey), CacheKey.ContentKeys.ControlCategory,
                () => controlRepository.GetByKey(controlKey));
        }

        #endregion

        #region Container methods

        public Container GetContainer(Guid containerId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ContainerId, SiteContext.Current.Site.Id, containerId), CacheKey.ContentKeys.ContainerCategory,
                () => containerRepository.Get(containerId));
        }

        public Container GetContainer(string markupId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ContainerMarkupId, SiteContext.Current.Site.Id, markupId), CacheKey.ContentKeys.ContainerCategory,
                () => containerRepository.Get(markupId, SiteContext.Current.Site.Id));
        }

        public IList<Container> GetContainers()
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ContainerAll, SiteContext.Current.Site.Id), CacheKey.ContentKeys.ContainerCategory,
                () => containerRepository.GetAll(SiteContext.Current.Site.Id));
        }

        #endregion

        #region Module methods

        public Module GetModule(Guid moduleId)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ModuleId, moduleId), CacheKey.ContentKeys.ModuleCategory,
                () =>
                {
                    var module = moduleRepository.Get(moduleId);
                    this.ConvertXmlToProperties(module);
                    return module;
                });
        }

        public IList<Module> GetModules()
        {
            return CacheManager.Current.FromCache(CacheKey.ContentKeys.ModuleAll, CacheKey.ContentKeys.ModuleCategory,
                () =>
                {
                    var modules = moduleRepository.GetAll();
                    foreach (var item in modules)
                    {
                        this.ConvertXmlToProperties(item);
                    }
                    return modules;
                });
        }

        public IList<Module> GetModules(bool isInstallable)
        {
            return CacheManager.Current.FromCache(string.Format(CacheKey.ContentKeys.ModuleInstallableAll, isInstallable), CacheKey.ContentKeys.ModuleCategory,
                () =>
                {
                    var modules = moduleRepository.GetAll(isInstallable);
                    foreach (var item in modules)
                    {
                        this.ConvertXmlToProperties(item);
                    }
                    return modules;
                });
        }

        #endregion
    }
}
